﻿using AppEventLib;
using AppEvents.JsonModel;
using MebApp.Launcher.Model;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MebApp.Launcher
{
    public class AppClient
    {
        public event EventHandler<Exception> Error;
        RestClient client;
        public string BaseUrl;
        public List<Cookie> Cookies { get; private set; }

        public string UserID { get; internal set; }

        public AppClient(string baseUrl)
        {
            Cookies = new List<Cookie>();
            this.BaseUrl = baseUrl;
            client = new RestClient(baseUrl);
        }

        public string DownloadUpdateXml(Guid id, int version)
        {
            var req = LoadRequest($"api/app/downloadupdatexml?id={id}&version={version}");
            var resp = client.Execute(req);
            if (resp.ErrorException != null)
            {
                Error?.Invoke(this, resp.ErrorException);
                return null;
            }
            else if (resp.RawBytes == null || resp.RawBytes.Length == 0)
            {
                Error?.Invoke(this, new Exception("下载失败，没有获取到数据。"));
                return null;
            }
            else if (resp.ContentType.IndexOf("json") != -1)
            {
                var json = JObject.Parse(resp.Content);
                Error?.Invoke(this, new Exception(json["msg"].Value<string>()));
                return null;
            }
            else if ((int)resp.StatusCode < 400)
            {
                return Helpers.FileHelper.WriteTemp(resp.RawBytes);
            }
            else
            {
                throw new Exception(resp.Content);
            }
        }

        internal void AppBugReport(Guid appId, string appFileName, string installPath, Exception ex)
        {
            try
            {
                //Guid appId, string appFileName, string installPath, string message, string stackTrace
                var req = LoadRequest($"api/app/AppBugReport");
                req.AddParameter("appId", appId);
                req.AddParameter("appFileName", appFileName);
                req.AddParameter("installPath", installPath);
                req.AddParameter("message", ex.Message);
                req.AddParameter("stackTrace", ex.StackTrace);
                client.Execute(req);
            }
            catch (Exception e)
            {
                Debugger.Break();
            }
        }

        /// <summary>
        /// 不要用这个了，大文件很慢| 现在使用DownloadUpdateXml 然后启动一个MebAppInstaller进程来安装
        /// </summary>
        /// <param name="id"></param>
        /// <param name="version"></param>
        /// <returns></returns>
        public string DownloadApp(Guid id, int version)
        {
            var req = LoadRequest($"api/app/download?id={id}&version={version}");
            var resp = client.Execute(req);
            if (resp.ErrorException != null)
            {
                Error?.Invoke(this, resp.ErrorException);
                return null;
            }
            else if (resp.RawBytes == null || resp.RawBytes.Length == 0)
            {
                Error?.Invoke(this, new Exception("下载失败，没有获取到数据。"));
                return null;
            }
            else if (resp.ContentType.IndexOf("json") != -1)
            {
                var json = JObject.Parse(resp.Content);
                Error?.Invoke(this, new Exception(json["msg"].Value<string>()));
                return null;
            }
            else if ((int)resp.StatusCode < 400)
            {
                return Helpers.FileHelper.WriteTemp(resp.RawBytes);
            }
            else
            {
                throw new Exception(resp.Content);
            }
        }

        /// <summary>
        /// 检查更新
        /// </summary>
        /// <param name="check"></param>
        /// <returns></returns>
        public JsonResp GetAppUpdates(List<UpdateCheckItem> check)
        {
            if (check.Any())
            {
                var request = LoadRequest("api/app/GetAppUpdates");
                request.AddParameter("list", JsonConvert.SerializeObject(check));
                return GetResponse(request);
            }
            return null;
        }

        public JsonResp GetApps(string kw, int? cagetory, int page)
        {
            var request = LoadRequest("api/app/getapps");
            request.AddParameter("kw", kw);
            request.AddParameter("cagetory", cagetory);
            request.AddParameter("page", page);
            return GetResponse(request);
        }
        public JsonResp Register(string name, string email, string message)
        {
            var request = LoadRequest("api/user/register");
            request.AddParameter("realName", name);
            request.AddParameter("email", email);
            request.AddParameter("message", message);
            return GetResponse(request);
        }

        public JsonResp Login(string user, string password)
        {
            RestSharp.RestRequest request = LoadRequest("api/user/login");
            request.AddParameter("username", user);
            request.AddParameter("password", password);
            return GetResponse(request);
        }

        #region helper methods from request
        private RestRequest LoadRequest(string apiUrl)
        {
            var request = new RestSharp.RestRequest(apiUrl, RestSharp.Method.POST);
            foreach (var cookie in Cookies)
            {
                request.AddCookie(cookie.Name, cookie.Value);
            }
            return request;
        }

        /// <summary>
        /// 使用情况
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        internal JsonResp GetUserApp(Guid id)
        {
            RestSharp.RestRequest request = LoadRequest("api/app/GetUserApp");
            request.AddParameter("id", id);
            return GetResponse(request);
        }

        internal void AddAppInstall(Guid id)
        {
            RestSharp.RestRequest request = LoadRequest("api/app/AddAppInstall");
            request.AddParameter("id", id);
            GetResponse(request);
        }

        public void RemoveAppInstall(Guid id)
        {
            RestSharp.RestRequest request = LoadRequest("api/app/RemoveAppInstall");
            request.AddParameter("id", id);
            GetResponse(request);
        }

        private JsonResp GetResponse(RestRequest request)
        {
            var resp = client.Execute<JsonResp>(request);
            if (resp.ErrorException != null)
            {
                Error?.Invoke(this, resp.ErrorException);
                return null;
            }
            else if ((int)resp.StatusCode >= 400)
            {
                Error?.Invoke(this, new Exception(resp.StatusDescription, resp.Content != null ? new Exception(resp.Content) : null));
                return null;
            }
            Parameter cookie = null;
            if ((cookie = resp.Headers.FirstOrDefault(x => x.Name == "Set-Cookie")) != null)
            {
                lock (Cookies)
                {
                    var pair = cookie.Value.ToString().Split(new char[] { '=' }, 2);
                    var c = new Cookie { Name = pair[0], Value = GetCookieValue(pair[1]) };
                    var index = Cookies.FindIndex(x => x.Equals(c));
                    if (index != -1)
                    {
                        Cookies[index] = c;
                    }
                    else
                        Cookies.Add(c);
                }
            }
            return resp.Data;
        }

        internal AppJson GetNewVersion(Guid appId, int version)
        {
            var request = LoadRequest("api/app/GetNewVersion");
            request.AddParameter("id", appId);
            request.AddParameter("version", version);
            var resp = GetResponse(request);
            if (resp != null && resp.code == 200)
            {
                return resp.As<AppJson>();
            }
            return null;
        }

        internal void IncreaseCorRun(string appId, string appVersion)
        {
            var request = LoadRequest("api/app/IncreaseCorRun");
            request.AddParameter("id", appId);
            request.AddParameter("version", appVersion);
            var resp = GetResponse(request);
        }

        internal void IncreaseAppRun(string appId, string appVersion)
        {
            var request = LoadRequest("api/app/IncreaseAppRun");
            request.AddParameter("id", appId);
            request.AddParameter("version", appVersion);
            var resp = GetResponse(request);
        }


        private string GetCookieValue(string value)
        {
            var array = value.Split(new string[] { "; " }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var item in array)
            {
                if (item.IndexOf("httponly") == 0
                    || item.IndexOf("path") == 0
                    || item.IndexOf("domain") == 0
                    )
                    continue;
                return item;
            }
            return string.Empty;
        }

        private T GetResponse<T>(RestRequest request)
        {
            return GetResponse(request).As<T>();
        }
        #endregion
    }
}
